package com.googlecode.flair.flexsdk;

import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.jdom.Element;

public class FlexComponentClass {

	private String packageName;
	private String className;
	private List<FlexStyle> styles = new Vector<FlexStyle>();
	private FlexComponentClass parent = null;
	private Map<String, StringBuffer> excludedStuff;
	private Map<String, String> propertyArrayTypes = new Hashtable<String, String>();
	
	
	public FlexComponentClass(String packageName, String className) {
		this.packageName = packageName;
		this.className = className;
	}

	public void addStyle(FlexStyle style) {
		this.styles.add(style);
		style.setComponentClass(this);
	}

	private Element getStylesElement() {
		Element stylesElement = new Element("styles");
		List<FlexStyle> inherited = getInheritedStyleList();
		
		StringBuffer inheritedStyleNames = new StringBuffer();
		for (FlexStyle style : inherited) {
			if (style.getName().endsWith("Skin")) {
				continue;
			}
			if (inheritedStyleNames.length() > 0) {
				inheritedStyleNames.append(' ');
			}
			inheritedStyleNames.append(style.getName());
		}
		
		stylesElement.addContent(new Element("inherited").setText(inheritedStyleNames.toString()));
		
		
		StringBuffer ownElements = new StringBuffer();
		for (FlexStyle flexStyle : styles) {
			if (ownElements.indexOf(flexStyle.getName()) == -1 && inheritedStyleNames.indexOf(flexStyle.getName()) == -1) {
				if (flexStyle.getName().endsWith("Skin")) {
					continue;
				}
				if (ownElements.length() > 0) {
					ownElements.append(" ");
				}
				ownElements.append(flexStyle.getName());
			}
		}
		stylesElement.addContent(new Element("specific").setText(ownElements.toString()));
		return stylesElement;
	}

	private List<FlexStyle> getInheritedStyleList() {
		List<FlexStyle> theStyles = new Vector<FlexStyle>();
		List<FlexStyle> parentStyles = new Vector<FlexStyle>();
		FlexComponentClass theParent = parent;
		while (theParent != null) {
			parentStyles.addAll(theParent.styles);
			theParent = theParent.parent;
		}
		if (parentStyles != null) {
			String exclusions = "";
			if (excludedStuff != null && excludedStuff.containsKey("styles")) {
				exclusions = excludedStuff.get("styles").toString();
			}
			Collections.sort(parentStyles, new Comparator<FlexStyle>() {
				
				public int compare(FlexStyle o1, FlexStyle o2) {
					return (o1.getName().compareTo(o2.getName()));
				}
			});
			for (FlexStyle flexStyle : parentStyles) {
				if (!exclusions.contains(flexStyle.getName())) {
					theStyles.add(flexStyle);
				}
			}
		}
		//theStyles.addAll(styles);
		return theStyles;
	}
	
	public List<FlexStyle> getAllStyles() {
		List<FlexStyle> allStyles = new Vector<FlexStyle>();
		allStyles.addAll(getInheritedStyleList());
		allStyles.addAll(styles);
		return allStyles;
	}
	
	public List<FlexStyle> getStyles() {
		return styles;
	}

	public void setExclusions(Map<String, StringBuffer> excludedStuff) {
		this.excludedStuff = excludedStuff;
	}

	public void setParent(FlexComponentClass parent) {
		this.parent = parent;
	}
	
	public String getClassName() {
		return className;
	}

	public void addPropertyArrayType(String property, String arrayType) {
		propertyArrayTypes.put(property, arrayType);
	}

	public Element toXml() {
		Element component = new Element("component");
		component.setAttribute("name", packageName + className);
		if (parent != null) {
			component.setAttribute("extend", parent.packageName + parent.className);
		}
		component.addContent(getStylesElement());
		component.addContent(getArrayTypesElement());
		component.addContent(getExcludedPropertiesElement());
		component.addContent(getExcludedEventsElement());
		return component;
	}

	private Element getArrayTypesElement() {
		Element arrayTypesElement = new Element("arrayTypes");
		for (String property : propertyArrayTypes.keySet()) {
			final Element typeElement = new Element("prop")
				.setAttribute("name", property)
				.setAttribute("type", propertyArrayTypes.get(property));
			arrayTypesElement.addContent(typeElement);
		}
		return arrayTypesElement;
	}
	
	private Element getExcludedPropertiesElement() {
		Element excludedPropertiesElement = new Element("excludedProperties");
		if (excludedStuff != null && excludedStuff.get("property") != null) {
			StringBuffer excludedProperties = excludedStuff.get("property");
			excludedPropertiesElement.setText(" " + excludedProperties.toString() + " ");
		}
		return excludedPropertiesElement;
	}
	
	private Element getExcludedEventsElement() {
		Element excludedEventsElement = new Element("excludedEvents");
		if (excludedStuff != null && excludedStuff.get("event") != null) {
			StringBuffer excludedEvents = excludedStuff.get("event");
			excludedEventsElement.setText(" " + excludedEvents.toString() + " ");
		}
		return excludedEventsElement;
	}
	
}
